/*******************************************************************************
 * Package: com.hngtrust.dualrecord.filter
 * Type:    AuthorityFilter
 * Date:    2019/12/25 14:13
 * 
 * Copyright (c) 2019 HUANENG GUICHENG TRUST CORP.,LTD All Rights Reserved.
 * 
 * You may not use this file except in compliance with the License.
 *******************************************************************************/
package com.hngtrust.iir.filter;

import com.hngtrust.framework.id.service.MyIdGenerator;
import com.hngtrust.framework.security.util.SecurityUtils;
import com.hngtrust.iir.base.entity.LogInfo;
import com.hngtrust.iir.base.service.LogInfoService;
import com.hngtrust.iir.util.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author Chentianyong
 */
@Slf4j
@Component("logFilter")
public class LogFilter implements Filter {

    /**
     * 主键生成器
     */
    @Autowired
    private MyIdGenerator myIdGenerator;
    
    @Autowired
    private LogInfoService logInfoService;
    
    /**
     * 不需要记录日志的api列表，每个api pattern支持Ant风格，如：/user/detail,/user/**, /user/add?User
     */
    private List<String> excludeUrls;
    
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        this.excludeUrls = new ArrayList<>();
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
        try {
            HttpServletRequest servletRequest = (HttpServletRequest) request;
            String path = servletRequest.getRequestURI();
            
            PathMatcher pathMatcher = new AntPathMatcher();
            
            // 检查是否是不需要记录日志的url
            for (String pattern : excludeUrls) {
                if (pathMatcher.match(pattern.trim(), path)) {
                    chain.doFilter(request, response);
                    return;
                }
            }
    
            response.setCharacterEncoding("UTF-8");
            HttpServletResponse servletResponse = (HttpServletResponse) response;
            
            Date startDate = new Date();
            long startTimeMillis = System.currentTimeMillis();
            
            chain.doFilter(servletRequest, servletResponse);
            
            long endTimeMillis = System.currentTimeMillis();
            //记录日志
            logSave(servletRequest, servletResponse, startDate,endTimeMillis - startTimeMillis);
        } catch (Exception ex) {
            log.error("日志获取接口信息失败", ex);
        }
    }
    
    @Override
    public void destroy() {
        // do nothing
    }
    
    /**
     * 记录日志
     * @param servletRequest
     * @param response
     */
    private void logSave(HttpServletRequest servletRequest, HttpServletResponse response, Date startDate, long executeTime) {
        try {
            String ip = HttpUtils.getIpAddressByCDN(servletRequest);
            String method = servletRequest.getMethod();
            String requestContentType = servletRequest.getContentType();
            String requestUri = servletRequest.getRequestURI();
            Long userId = 0L;
            if(null != SecurityUtils.getLoginUser()) {
                userId = Long.parseLong(SecurityUtils.getLoginUser().getId());
            }
            // 处理返回结果及记录日志表
            String responseContentType = response.getContentType();
            //接口类型
            Integer packageType = 0;

            Long logId = myIdGenerator.nextId();
            
            LogInfo logData = new LogInfo();
            logData.setId(logId);
            logData.setUserId(userId);
            logData.setRequestIp(ip);
            logData.setPackageType(packageType);
            logData.setRequestMethod(method);
            logData.setRequestType(requestContentType);
            logData.setResponseType(responseContentType);
            logData.setRequestUrl(requestUri);
            logData.setStartTime(startDate);
            logData.setExecuteTimes(executeTime);
            logData.setCreateTime(new Date());
            
            logInfoService.add(logData);
        } catch (Exception ex) {
            log.error("日志写入失败", ex);
        }
    }
}
